import schedulegui.gui.*;
import schedulegui.data.*;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
import java.util.Date;
import java.util.Set;
import java.util.HashSet;
import java.util.Calendar;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
/**
 * This is the gui of the festival. This class also contains a private class that implements the callBackInterface-interface. This gui shows you a list of events performed on the Mi-festival.
 * You can get information of all the events including playlist of the bands. Write comments, like performances, attend to them, search for them, you can do all this with an account, for witch you have to give your 
 * name,e-mailadress, age and gender.
 * You can also access to a menu, where you can edit your account but also ask the statistics of the festival (most liked, most comments, most attended).
 * 
 * @author Mathieu Reymond and Jonathan Smet
 * @version 11/05/2011
 */
public class Gui
{
    private GuiController gui = new GuiController(new CallBackHandler());
    private String lineUpNames[];
    private List<InfoItem> mainStage = new ArrayList<InfoItem>();
    private List<InfoItem> marquee = new ArrayList<InfoItem>();
    private List<InfoItem> club = new ArrayList<InfoItem>();
    private LinkedHashMap<String, List<InfoItem>> list = new LinkedHashMap<String, List<InfoItem>>();
    private User currentUser = null;
    
     /**
     * The creation of a new gui.
     */
    public Gui()
    {
        LineUp.setLineUp();
        
        lineUpNames = LineUp.getNameList();
        for(int index = 0; index < lineUpNames.length; index++)
        {
            if(LineUp.getLineUp().get(lineUpNames[index]).getPodium() == "Main Stage")
            {
                mainStage.add(LineUp.getLineUp().get(lineUpNames[index]));
            }
            else if(LineUp.getLineUp().get(lineUpNames[index]).getPodium() == "Marquee")
            {
                marquee.add(LineUp.getLineUp().get(lineUpNames[index]));
            }
            else
            {
                club.add(LineUp.getLineUp().get(lineUpNames[index]));
            }
        }
        
        list.put("Main Stage", mainStage);
        list.put("Marquee", marquee);
        list.put("Club", club);
        
        gui.showGui();
        gui.sleep(1000);
        gui.setSchedule(list);
        
        runGui();
        
    }
    
     /**
     * Runs the gui once you are logged in.
     */
    public void runGui()
    {
        account();
        gui.showMessagePanel("Welcome, " + currentUser.getName());
        
        gui.updateSchedule(mainStage.get(0).getStartDate(), list);
    }
    
    /**
     * The methode allows you to create an account or log in with an existing account.
     */
    private void account()
    {
        while(currentUser == null)
        {
            boolean result;
            String userName;
            String userEmail;
            String password;
            String passwordCheck;
            String fName;
            String lName;
            int year;
            int month;
            int day;
            boolean userGender;
            
            Set<String> login = new HashSet<String>();
            login.add("Create a new account");
            login.add("Log in");
        
            String logChoice = gui.showChoicePanel("Hello, please log in !", login);
        
            if(logChoice.equals("Log in"))
            {
                userEmail = gui.showInputPanel("Please enter your email");
                password = gui.showPasswordPanel("Please enter your password");
                currentUser = Account.loggin(userEmail, password);
                if(currentUser == null)
                {
                    gui.showMessagePanel("Sorry, the combinaison email-password didn't match, please try again");
                }
            }
            else
            {
                do
                {
                    userName = gui.showInputPanel("Enter your UserName :");
                    result = Account.userCheck(userName);
                    if(result)
                    {
                        gui.showMessagePanel("Sorry, this name is already used");    
                    }
                    
                } while(result);
                
                do
                {
                    userEmail = gui.showInputPanel("Enter your email :");
                    result = Account.emailCheck(userEmail);
                    if(result)
                    {
                        gui.showMessagePanel("Sorry, this email is already used");
                    }
                } while(result);
                
                do
                {
                    password = gui.showPasswordPanel("Enter your password :");
                    passwordCheck = gui.showPasswordPanel("Enter your password again :");
                    
                    if(!password.equals(passwordCheck))
                    {
                        gui.showMessagePanel("Sorry, you typed two different passwords");
                    }
                    
                } while((!password.equals(passwordCheck)));
                
                fName = gui.showInputPanel("Enter your first name :");
                lName = gui.showInputPanel("Enter your last name :");
                
                do
                {
                    try
                    {
                        year = Integer.parseInt(gui.showInputPanel("Enter your birth date (year) :"));
                    }
                    catch (NumberFormatException exception)
                    {
                        year = 0;
                    }
          
                    if(year < 1900 || year > 2011)
                    {
                        gui.showMessagePanel("Sorry, not a valid number");
                    }
                } while(year < 1900 || year > 2011);
                
                do
                {
                    try
                    {
                        month = Integer.parseInt(gui.showInputPanel("Enter your birth date (month) :"));
                    }
                    catch (NumberFormatException exception)
                    {
                        month = 0;
                    }
                    
                    if(month <1 || month > 12)
                    {
                        gui.showMessagePanel("Sorry, not a valid number");
                    }
                } while(month <1 || month > 12);
                
                do
                {
                    try
                    {
                        day = Integer.parseInt(gui.showInputPanel("Enter your birth date (day) :"));
                    }
                    catch (NumberFormatException exception)
                    {
                        day = 0;
                    }
                    
                    if(!dayCheck(month, day))
                    {
                        gui.showMessagePanel("Sorry, not a valid number");
                    }
                    
                } while(!dayCheck(month, day));
                
                HashSet<String> gender = new HashSet<String>();
                gender.add("Male");
                gender.add("Female");
                
                String genderChoice = gui.showChoicePanel("Choose your gender :", gender);
                if(genderChoice.equals("Male"))
                {
                    userGender = true;
                }
                else
                {
                    userGender = false;
                }
                
                boolean finalResult = Account.createUser(userName, userEmail, password, year, month, day, userGender, fName, lName);
                
                if(!finalResult)
                {
                    gui.showMessagePanel("Error !");
                }
                else
                {
                    gui.showMessagePanel("Your account is succesfully created !");
                }
            }
        }
        gui.setGuiTitle("Hello, " + currentUser.getName() + " !");
        initialisation();
        
    }
    
    /**
     * This methode checkes if a specific day exists in a specific month. E.g. The 31st day of June doesn't exist
     * 
     * @param monthToCheck The number of the month you want to check (1: January, 12: December)
     * @param day The day of the month you want to check.
     * 
     * @return true if the day exists false otherwise
     */
    private boolean dayCheck(int monthToCheck, int day)
    {
        boolean result = false;
        double month = monthToCheck;
        double month_2 = month%2;
        
        if(day >0)
        {
            if( (((month > 0 && month < 8 && month != 2) && month_2 == 0 && day < 31) || ((month > 7 && month <13) && month_2 !=0 && day <31) ))
            {
                result = true;
            }
            else if(((month > 0 && month < 8 && month != 2) && month_2 != 0 && day <32) || ((month > 7 && month <13) && month_2 ==0 && day <32)) 
            {
                result = true;
            }
            else if(month == 2 && day < 29)
            {
                result = true;
            }
        }
        
        return result;
    }
    
    /**
     * Initialises the likes and the attendings of a specific user's performances.
     */
    private void initialisation()
    {
         ArrayList<String> likeList = currentUser.getLikeList();
         ArrayList<String> planning = currentUser.getPlanning().getPlanningList();
        
        for(int index = 0; index < LineUp.getNameList().length; index++)
        {
            LineUp.getLineUp().get(LineUp.getNameList()[index]).setLike(false);
            LineUp.getLineUp().get(LineUp.getNameList()[index]).setAttending(false);
        }
        
        for(int index = 0; index < likeList.size(); index++)
        {
            LineUp.getLineUp().get(likeList.get(index)).setLike(true);
        }
        
        for(int index = 0; index < planning.size(); index++)
        {
            LineUp.getLineUp().get(planning.get(index)).setAttending(true);
        }
    }
    
    /**
     * This is the private class CallbackHandler, that implements CallBackInterface. In this class are written all the methodes that will be used when a user clics on a specific button of the gui.
     */
    private class CallBackHandler implements CallbackInterface
    {
        private Calendar calendarSet;
        
        public CallBackHandler()
        {
        }
        
        /**
     * Add a comment to a specified performance.
     * @param infoItem The infoItem (performance) you want to write a comment on.
     */
        public void addComment(InfoItem infoItem)
        {
            String comment = gui.showInputPanel("Please write your comment :");
            Performance performance = (Performance) infoItem;
            performance.writeComment(currentUser, comment);
        }
    
           /**
     * Allow the user to attend a specific performance 
     * @param infoItem The infoItem (performance) you want to attend.
     */
        public void attendItem(InfoItem infoItem)
        {
            Performance performance = (Performance) infoItem;
            ArrayList<String> free = currentUser.getPlanning().checkFree(performance.getTitle());
            if(!free.isEmpty())
            {
                String title = "";
                for(int index=0; index < free.size(); index++)
                {
                    if (index >0)
                    {
                        title += ", ";
                    }
                    title += free.get(index);
                    
                }
                title += " are overlapped, continue?";
                LinkedHashSet<String> choice = new LinkedHashSet <String>();
                choice.add("Yes");
                choice.add("No");
                String guiChoice = gui.showChoicePanel(title, choice);
                
                if(guiChoice.equals("Yes"))
                {
                    currentUser.getPlanning().addPerformance(performance.getTitle());
                    performance.setAttending(true);
                }
            }
                
            currentUser.getPlanning().addPerformance(performance.getTitle());
            performance.setAttending(true);
        }
    
           /**
     * Change the date of the gui. You'll have to write in the format HH:mm. The consequence of the date changement is the display of the gui. 
     * 
     */
        public void changeDate()
        {
            Date dateSet = gui.getTime();
            calendarSet = calendarSet.getInstance();
            calendarSet.setTime(dateSet);
            int hour;
            int minutes;
        
            String dateString = gui.showInputPanel("Choose a date (HH:mm) :");
            String newDate[] = dateString.split(":");
            try
            {
                hour = Integer.parseInt(newDate[0]);
                minutes = Integer.parseInt(newDate[1]);
            }
            catch (Exception exception)
            {
                hour = calendarSet.get(Calendar.HOUR);
                minutes = calendarSet.get(Calendar.MINUTE);
                gui.showMessagePanel("Not a valid date.");
            }
              
            calendarSet.set(11, Integer.parseInt(newDate[0])); // 11 is the hour (24 hour mode) field
            calendarSet.set(12, Integer.parseInt(newDate[1])); // 12 is the minutes field
            dateSet = calendarSet.getTime();
            gui.setTime(dateSet);
            gui.updateSchedule();
        }
    
           /**
     * Likes a specific performance 
     * @param infoItem The infoItem (performance) you want to like.
     */
        public void likeItem(InfoItem infoItem)
        {
            Performance performance = (Performance) infoItem;
            currentUser.like(performance.getTitle());
        }
    
           /**
     * This method allows the user to search in the performances and the other registered users. The longuests matching words will be first on the list, the performances will be put before the users. 
     * This method displays a maximum of 15 results.
     * @param searchString The words you want to look for.
     */
        public void searchItem(String searchString)
        {
            LinkedHashSet <String> results = LineUp.SearchPerf(searchString);
            results.addAll(UserData.SearchUser(searchString));
            results.add("Close");
            
            String choice = gui.showChoicePanel("Results: ", results);
            HashMap <String, Performance> performance = LineUp.getLineUp(); 
            Performance perfChoice = performance.get(choice);
            User userChoice = UserData.getUserData().get(choice);
            
            if(perfChoice !=null)
            {
                showDetails(perfChoice);
            }
            if(userChoice != null)
            {
                gui.showTextPanel(userChoice.getName() , UserData.getUserData().get(userChoice.getName()).showInfo());
            }
                      
            
        }
    
           /**
     * Show all the comments of a performance 
     * @param infoItem The infoItem (performance) you want to get the comments of.
     */
        public void showComments(InfoItem infoItem)
        {
            Performance performance = (Performance) infoItem;
            ArrayList<Comment> comments = performance.getComments();
            String commentString = "";
            
            for(int index = 0; index < comments.size(); index++)
            {
                commentString += comments.get(index).getUserName() + " wrote : " + "\""+ comments.get(index).getComment() + "\"\n\n";
            }
            
            if( commentString == "")
            {
                commentString = "There aren't any comments.";
            }
            
            gui.showTextPanel(performance.getTitle() + " (Comments) :", commentString);
            
        }
    
           /**
     * Shows the details of a specific performance 
     * @param infoItem The infoItem (performance) you want to know the details of
     */
        public void showDetails(InfoItem infoItem)
        {
            Performance performance = (Performance) infoItem;
            gui.showTextPanel(performance.getTitle(),performance.getDetails() );

        }
    
           /**
     * Show the menu (when the user clics on the menu-button). In this menu the user can visualise his planning (he can go back to the global schedule by clicking on the "main button").
     * The user can also edit his account, see the statistics, his comments and his likes. He can also log-out.
     * 
     */
        public void showMenu()
        {
            LinkedHashSet<String> menu = new LinkedHashSet <String>();
            menu.add("Planning");
            menu.add("Account");
            menu.add("Statistics");
            menu.add("My Comments");
            menu.add("My Likes");
            menu.add("Log Out");
            menu.add("Main Page");
            
            String choice = gui.showChoicePanel("Menu", menu);
            if (choice.equals("Planning"))
            {
                ArrayList<String> planningList = currentUser.getPlanning().getPlanningList();
                
                if(!planningList.isEmpty())
                {
                    List<InfoItem> userMainStage = new ArrayList<InfoItem>();
                    List<InfoItem> userMarquee = new ArrayList<InfoItem>();
                    List<InfoItem> userClub = new ArrayList<InfoItem>();
                    LinkedHashMap<String, List<InfoItem>> userList = new LinkedHashMap<String, List<InfoItem>>();
                
                    for(int index = 0; index < planningList.size(); index++)
                    {
                        if(LineUp.getLineUp().get(planningList.get(index)).getPodium() == "Main Stage")
                        {
                            userMainStage.add(LineUp.getLineUp().get(planningList.get(index)));
                        }
                        else if(LineUp.getLineUp().get(planningList.get(index)).getPodium() == "Marquee")
                        {
                            userMarquee.add(LineUp.getLineUp().get(planningList.get(index)));
                        }
                        else
                        {
                            userClub.add(LineUp.getLineUp().get(planningList.get(index)));
                        }
                    }
                
                    userList.put("Main Stage", userMainStage);
                    userList.put("Marquee", userMarquee);
                    userList.put("Club", userClub);
                    gui.setSchedule(userList);
                    gui.updateSchedule(LineUp.getLineUp().get(planningList.get(0)).getStartDate(), userList);
                }
                
            }
            
            if (choice.equals("Account"))
            {
                LinkedHashSet<String> subMenuAccount = new LinkedHashSet<String>(); 
                subMenuAccount.add("Show Details");
                subMenuAccount.add("Change Password");
                subMenuAccount.add("Change e-mailadress");
                subMenuAccount.add("Delete Account");
                
                String subChoice = gui.showChoicePanel("Your Account", subMenuAccount);
                if (subChoice.equals("Show Details"))
                {
                    String info = currentUser.showInfo();
                    gui.showTextPanel("Your Account", info);                    
                }  
                if (subChoice.equals("Change Password"))
                {
                    String password = null;
                    String passwordCheck = null;
                    String oldPassword = null;
                    
                    LinkedHashSet<String> confirmation = new LinkedHashSet<String>(); 
                    confirmation.add("Yes");
                    confirmation.add("No");
                    String confirm = gui.showChoicePanel("Are you sure ?", confirmation);
                    
                    if(confirm.equals("Yes"))
                    {
                        do
                        {

                            oldPassword = gui.showPasswordPanel("Enter your old password :");
                        
                            if(oldPassword.equals(currentUser.getPassword()))
                            {
                                password = gui.showPasswordPanel("Enter your new password :");
                                passwordCheck = gui.showPasswordPanel("Enter your new password again :");
                    
                                if(!password.equals(passwordCheck))
                                {
                                    gui.showMessagePanel("Sorry, you typed two different passwords");
                                }
                            }
                            else
                            {
                                gui.showMessagePanel("Sorry, you typed the wrong password");
                            }   
                    
                        } while((!password.equals(passwordCheck)) ||(! oldPassword.equals(currentUser.getPassword())));
                        currentUser.changePassword(password, oldPassword);
                    }
                
                }
                if (subChoice.equals("Change e-mailadress"))
                {
                    String newEmail = gui.showInputPanel("Please enter your new e-mailadress : ");
                    if(!Account.emailCheck(newEmail))
                    {
                        currentUser.setEmail(newEmail);
                    }
                    else
                    {
                        gui.showMessagePanel("This e-mail is already used");
                    }
                    
                }
                if (subChoice.equals("Delete Account"))
                {
                    LinkedHashSet<String> confirmation = new LinkedHashSet<String>(); 
                    confirmation.add("Yes");
                    confirmation.add("No");
                    String confirm = gui.showChoicePanel("Are you sure ?", confirmation);
                    String inputPassword = null;
                    
                    if(confirm.equals("Yes"))
                    {
                        int t = 0;
                        do
                        {
                            inputPassword = gui.showPasswordPanel("Type your password : ");
                            t++;
                        }while(t<3 &&  !inputPassword.equals(currentUser.getPassword()));
                        
                        Account.deleteAccount(currentUser.getName());
                        currentUser = null;
                        runGui();
                    }
                }
                
            }
            if (choice.equals("Statistics"))
            {
                 LinkedHashSet<String> subMenuStat = new LinkedHashSet<String>(); 
                subMenuStat.add("Most Liked");
                subMenuStat.add("Most Planned");
                subMenuStat.add("Most Comments");
                subMenuStat.add("Close");
                
                String statChoice = gui.showChoicePanel("Statistics : ", subMenuStat);
                
                if (statChoice.equals("Most Liked"))
                {
                    LinkedHashSet<String> mostLiked = Statistics.mostLiked();
                    mostLiked.add("Close");
                    
                    String mostLikedChoice = gui.showChoicePanel("Most Liked", mostLiked);
                    showDetails((InfoItem) LineUp.getLineUp().get(mostLikedChoice));
                }
                if (statChoice.equals("Most Planned"))
                {
                    LinkedHashSet<String> mostAttend = Statistics.mostAttend();
                     mostAttend.add("Close");

                    String mostAttendChoice = gui.showChoicePanel("Most Planned", mostAttend);
                    showDetails((InfoItem) LineUp.getLineUp().get(mostAttendChoice));
                }
                if (statChoice.equals("Most Comments"))
                {
                    LinkedHashSet<String> mostComments = Statistics.mostComment();
                     mostComments.add("Close");
                    String mostCommentChoice = gui.showChoicePanel("Most Comments", mostComments);
                    showDetails((InfoItem) LineUp.getLineUp().get(mostCommentChoice));
                    
                }
                
            }
            if (choice.equals("My Comments"))
            {
                ArrayList<Comment> myComments = UserData.getUserComments(currentUser);
                String userComment = "";
                
                for(int index =0; index < myComments.size(); index++)
                {
                    userComment += "You wrote (on performance : " + myComments.get(index).getPerformanceName() + ") : " +  myComments.get(index).getComment() + "\n";
                }
                
                gui.showTextPanel("My Comments : ", userComment);
            }
            if (choice.equals("My Likes"))
            {   
                ArrayList<String> likeList = currentUser.getLikeList();
                LinkedHashSet<String> showLikeList = new LinkedHashSet<String>();
                showLikeList.addAll(likeList);
                
                String likeChoice = gui.showChoicePanel("Your Likes :", showLikeList);
                showDetails((InfoItem) LineUp.getLineUp().get(likeChoice));
            }
            if (choice.equals("Log Out"))
            {
                currentUser = null;
                runGui();
            }
            
            if (choice.equals("Main Page"))
            {
                lineUpNames = LineUp.getNameList();
                for(int index = 0; index < lineUpNames.length; index++)
                {
                    if(LineUp.getLineUp().get(lineUpNames[index]).getPodium() == "Main Stage")
                    {
                        mainStage.add(LineUp.getLineUp().get(lineUpNames[index]));
                    }
                    else if(LineUp.getLineUp().get(lineUpNames[index]).getPodium() == "Marquee")
                    {
                        marquee.add(LineUp.getLineUp().get(lineUpNames[index]));
                    }
                    else
                    {
                        club.add(LineUp.getLineUp().get(lineUpNames[index]));
                    }
                }
                
                list.clear();
                list.put("Main Stage", mainStage);
                list.put("Marquee", marquee);
                list.put("Club", club);
                gui.setSchedule(list);
                gui.updateSchedule(mainStage.get(0).getStartDate(), list);
            }
            
        }
    
           /**
     * Allows you to unattend an attended performance.
     * @param infoItem The infoItem (performance) you want to unattend
     */
        public void unattendItem(InfoItem infoItem)
        {
            Performance performance = (Performance) infoItem;
            currentUser.getPlanning().removePerformance(performance.getTitle());
            performance.setAttending(false);
        }
    
           /**
     * Allows you to "unlike"  a liked performance
     * @param infoItem The infoItem (performance) you want to unlike
     */
        public void unlikeItem(InfoItem infoItem)
        {
            Performance performance = (Performance) infoItem;
            currentUser.like(performance.getTitle());
        }
        
           /**
     * Get the user that is currently logged in
     * @return The user that is currently connected.
     */
        public User getUser()
        {
            return currentUser;
        }
    }
    

}



